home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Texteditors / Origami / Sources / src / keybind / optmac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-27  |  48.5 KB  |  1,153 lines

  1. /*{{{}}}*/
  2. /*{{{  #includes*/
  3. #include <ctype.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7.  
  8. #define OPTMAC_C
  9.  
  10. #include "keybind.h"
  11. /*}}}  */
  12.  
  13. #ifndef NO_OPTI
  14.    /*{{{  next_command*/
  15. #   include <h/codelg.h>
  16.  
  17.    private TOKEN *next_command(TOKEN *x)
  18.    { if (*x>O_EXE_MACRO || *x<O_NOP) return(x+1);
  19.      switch (cmd_type[*x-O_NOP])
  20.       { case COM_II:
  21.            x++;
  22.         case COM_I:
  23.         case COM_C:
  24.         case COM_A:
  25.            return(x+2);
  26.         case COM_IIP:
  27.            x++;
  28.         case COM_IP:
  29.            x++;
  30.         case COM_P:
  31.            x++;
  32.            while (*x!=M_END_MACRO)
  33.               if (*x==M_INT_STRING) x+=2; else x++;
  34.         case COM:
  35.            return(x+1);
  36.         default:
  37.            fprintf(stderr,"CRASH\n");
  38.            kbd_exit(1);
  39.       }
  40.  
  41.      return(0);
  42.    }
  43.    /*}}}  */
  44.    /*{{{  jmp_dest*/
  45.    private TOKEN *jmp_dest(TOKEN *x)
  46.    {
  47.      switch(*x)
  48.       { CASES_M_CALL
  49.            return(x+1+*x-M_CALL_0);
  50.         CASES_M_JMP
  51.            return(x+1+*x-M_JMP_0);
  52.         CASES_M_JMP_FALSE
  53.            return(x+1+*x-M_JMP_FALSE_0);
  54.         CASES_M_JMP_TRUE
  55.            return(x+1+*x-M_JMP_TRUE_0);
  56.         case M_CALL:
  57.         case M_JMP:
  58.         case M_JMP_FALSE:
  59.         case M_JMP_TRUE:
  60.            return(x+2+*(x+1));
  61.         default:
  62.            break;
  63.       }
  64.      kbd_exit(1);
  65.    }
  66.    /*}}}  */
  67.    /*{{{  optmac*/
  68.    /*{{{  jumped_on, uses jmp-information, stored in buff*/
  69.    /*{{{  jumped_on_loop*/
  70.    private boolean jumped_on_loop(TOKEN *from,TOKEN *to,TOKEN *start,TOKEN *buff)
  71.    {
  72.      to=buff+(to-start);
  73.      from=buff+(from-start);
  74.      while (from<to)
  75.         if (*from++)
  76.            return(True);
  77.      return(False);
  78.    }
  79.    /*}}}  */
  80. #   define jumped_on(from,to) jumped_on_loop(from,to,start,buff)
  81.    /*}}}  */
  82.  
  83. #   define STR_CUT_LG 2
  84.    public TOKEN *opt_mac
  85.                   ( TOKEN *start,
  86.                     TOKEN *end,
  87.                     boolean no_not_opt,
  88.                     boolean rc_string_gen,
  89.                     boolean fix_args
  90.                   )
  91.    {
  92.      /*{{{  variables*/
  93.      boolean changed;
  94.      int loop,loop_max,s_jmp_cut,s_modified,s_shrink;
  95.      TOKEN buff[OCL_CODE_LEN];
  96.      enum
  97.       { pre_cut,
  98.         cut_strings,
  99.         set_no_test,
  100.         set_fixed_cmd,
  101.         opt_ready
  102.       } opt_type;
  103.      /*}}}  */
  104.  
  105.      loop=0;
  106.      loop_max=4*(end-start);
  107.      s_jmp_cut=s_shrink=s_modified=0;
  108.      opt_type=fix_args?set_fixed_cmd:pre_cut;
  109.      do
  110.       /*{{{  one optimisation step*/
  111.       { int jmp_cut,modified,shrink;
  112.  
  113.         changed=False;
  114.         jmp_cut=shrink=modified=0;
  115.         /*{{{  start->buff, jmp opt*/
  116.         { TOKEN *current,*dest,*next,*jmp;
  117.  
  118.           for (current=start,dest=buff;current!=end;)
  119.            { boolean inverse=False;
  120.  
  121.              next=next_command(current);
  122.              switch (*current)
  123.               { case M_CALL:
  124.                 case M_JMP:
  125.                  /*{{{  cut simple jmp-sequences*/
  126.                  { TOKEN typ= *current;
  127.                    int loop_max;
  128.  
  129.                    for
  130.                     ( loop_max=end-start,jmp=jmp_dest(current) ; jmp!=end ; )
  131.                     { switch (*jmp)
  132.                        { case O_NOP:
  133.                             jmp++;changed=True;jmp_cut++;continue;
  134.                          case M_JMP:
  135.                             if (loop_max--<0) break;
  136.                             jmp=jmp_dest(jmp);
  137.                             changed=True;
  138.                             jmp_cut++;
  139.                             continue;
  140.                          case M_NOT:
  141.                             if (no_not_opt) break;
  142.                             fprintf(stderr,"JMP-NOT optimizer crash\n");
  143.                             no_not_opt=True;
  144.                             next=start;
  145.                             dest=buff;
  146.                             continue;
  147.                          default:
  148.                             break;
  149.                        }
  150.                       break;
  151.                     }
  152.                    dest=generate_jmp(typ,dest,buff+(jmp-start));
  153.                    current=next;
  154.                    continue;
  155.                  }
  156.                  /*}}}  */
  157.                 case M_NOT:
  158.                  /*{{{  break, or prefix for jmp-condition*/
  159.                    if (no_not_opt)
  160.                     { *dest++ = *current++;continue; }
  161.                    else
  162.                     { do
  163.                        /*{{{  skip one NOT*/
  164.                        { inverse= !inverse;
  165.                          changed=True;
  166.                          jmp_cut++;
  167.                          *dest++ = O_NOP;
  168.                          current=next;
  169.                          next=next_command(current);
  170.                        }
  171.                        /*}}}  */
  172.                       while (*current==M_NOT && next!=end);
  173.                       if (current!=end && *current!=M_JMP_FALSE && *current!=M_JMP_TRUE)
  174.                        /*{{{  cannot optimize NOT's, this must be a tricky code!*/
  175.                        { fprintf(stderr,"JMP-NOT optimizer crash\n");
  176.                          no_not_opt=True;
  177.                          current=start;
  178.                          dest=buff;
  179.                          continue;
  180.                        }
  181.                        /*}}}  */
  182.                     }
  183.                  /*}}}  */
  184.                 case M_JMP_TRUE:
  185.                 case M_JMP_FALSE:
  186.                  /*{{{  handle jmp-sequences, value of tag is known*/
  187.                  { TOKEN typ;
  188.                    int loop_max;
  189.                    boolean tag_value;
  190.  
  191.                    tag_value= *current==M_JMP_TRUE;
  192.                    typ=tag_value?(inverse?M_JMP_FALSE:M_JMP_TRUE)
  193.                                 :(inverse?M_JMP_TRUE:M_JMP_FALSE);
  194.                    for
  195.                     ( loop_max=end-start,jmp=jmp_dest(current) ; jmp!=end ; )
  196.                     { switch (*jmp)
  197.                        { case O_NOP:
  198.                             jmp++;changed=True;jmp_cut++;continue;
  199.                          case M_JMP:
  200.                             if (loop_max--<0) break;
  201.                             jmp=jmp_dest(jmp);
  202.                             changed=True;
  203.                             jmp_cut++;
  204.                             loop_max--;
  205.                             continue;
  206.                          case M_NOT:
  207.                             if (no_not_opt) break;
  208.                             tag_value = !tag_value;
  209.                             jmp+=1;
  210.                             jmp_cut++;
  211.                             changed=True;
  212.                             continue;
  213.                          case M_JMP_FALSE:
  214.                             if (loop_max--<0) break;
  215.                             if (tag_value) jmp+=2; else jmp=jmp_dest(jmp);
  216.                             changed=True;
  217.                             jmp_cut++;
  218.                             continue;
  219.                          case M_JMP_TRUE:
  220.                             if (loop_max--<0) break;
  221.                             if (tag_value) jmp=jmp_dest(jmp); else jmp+=2;
  222.                             changed=True;
  223.                             jmp_cut++;
  224.                             continue;
  225.                          default:
  226.                             break;
  227.                        }
  228.                       break;
  229.                     }
  230.                    dest=generate_jmp(typ,dest,buff+(jmp-start));
  231.                    current=next;
  232.                    continue;
  233.                  }
  234.                  /*}}}  */
  235.                 default:
  236.                  /*{{{  copy the code*/
  237.                    for (;current!=next;*dest++ = *current++);
  238.                    continue;
  239.                  /*}}}  */
  240.               }
  241.            }
  242.         }
  243.         /*}}}  */
  244.         /*{{{  buff->start, shrink and modify to better code*/
  245.         { TOKEN *current,*next,*dest;
  246.  
  247.           /*{{{  mark reachable commands*/
  248.           for (current=start;current!=end;*current++ = O_NOP);
  249.           for (dest=end,start[0]=0;;)
  250.            {
  251.              if (dest==end)
  252.               /*{{{  look for next reached, unhandled command*/
  253.               {
  254.                 for (dest=start;dest!=end;) if (*dest==0) break; else dest++;
  255.                 if (dest==end) break;
  256.                 current=buff+(dest-start);
  257.                 continue;
  258.               }
  259.               /*}}}  */
  260.              else if (*dest!=M_END_MACRO)
  261.               /*{{{  handle a reachable, unhandled command*/
  262.               { *dest=M_END_MACRO;
  263.                 switch (*current)
  264.                  { case O_NOP:
  265.                       *dest=O_NOP;
  266.                       current++;
  267.                       dest++;
  268.                       continue;
  269.                    CASES_M_CALL      case M_CALL:
  270.                    CASES_M_JMP       case M_JMP:
  271.                    CASES_M_JMP_FALSE case M_JMP_FALSE:
  272.                    CASES_M_JMP_TRUE  case M_JMP_TRUE:
  273.                     /*{{{  mark jmp-dest*/
  274.                     { TOKEN *jmp;
  275.  
  276.                       jmp=start+(jmp_dest(current)-buff);
  277.                       if (jmp!=end && *jmp==O_NOP && jmp!=dest)
  278.                          *jmp=0;
  279.                     }
  280.                     /*}}}  */
  281.                    default:
  282.                     { boolean no_cont;
  283.  
  284.                       /*{{{  set no_cont to correct value, maybe set opt_end!*/
  285.                       switch (*current)
  286.                        { case M_EXIT:
  287.                          case M_END_MACRO:
  288.                          CASES_M_JMP
  289.                          case M_JMP:
  290.                             no_cont=True;
  291.                             break;
  292.                          default:
  293.                             no_cont=False;
  294.                        }
  295.                       /*}}}  */
  296.                       next=next_command(current);
  297.                       for (;current!=next;current++,*dest++=M_END_MACRO);
  298.                       if (no_cont)
  299.                          dest=end;
  300.                       continue;
  301.                     }
  302.                  }
  303.               }
  304.               /*}}}  */
  305.              else
  306.               {
  307.                 dest=end;
  308.               }
  309.             }
  310.           /*}}}  */
  311.           /*{{{  shrink code*/
  312.           { boolean shrinking;
  313.  
  314.             shrinking=False;
  315.             /*{{{  get new adresses*/
  316.             { int i;
  317.  
  318.               for (current=start,i=0;current!=end;current++)
  319.                  *current=((*current==M_END_MACRO)?i++:(shrinking=True,-1));
  320.               *end=i;
  321.             }
  322.             /*}}}  */
  323.             if (shrinking)
  324.              /*{{{  change jmps*/
  325.                for
  326.                 ( current=start
  327.                 ; current!=end
  328.                 ; current=start+(next_command(buff+(current-start))-buff)
  329.                 )
  330.                 { TOKEN *x;
  331.  
  332.                   if (*current!=-1)
  333.                    { switch(*(x=buff+(current-start)))
  334.                       { case M_CALL:
  335.                         case M_JMP:
  336.                         case M_JMP_FALSE:
  337.                         case M_JMP_TRUE:
  338.                            *(x+1)= start[jmp_dest(x)-buff]-(*current+2);
  339.                            break;
  340.                         CASES_M_CALL
  341.                            *x=M_CALL_0+start[jmp_dest(x)-buff]-(*current+1);
  342.                            break;
  343.                         CASES_M_JMP
  344.                            *x=M_JMP_0+start[jmp_dest(x)-buff]-(*current+1);
  345.                            break;
  346.                         CASES_M_JMP_FALSE
  347.                            *x=M_JMP_FALSE_0+start[jmp_dest(x)-buff]-(*current+1);
  348.                            break;
  349.                         CASES_M_JMP_TRUE
  350.                            *x=M_JMP_TRUE_0+start[jmp_dest(x)-buff]-(*current+1);
  351.                            break;
  352.                         default:
  353.                            break;
  354.                       }
  355.                    }
  356.                 }
  357.              /*}}}  */
  358.           }
  359.           /*{{{  copy and shrink, clear buff*/
  360.           for (current=start,dest=buff;current+shrink!=end;*dest++=0)
  361.              if (current[shrink]!=-1)
  362.                 *current++= *dest;
  363.              else
  364.                 shrink++;
  365.           end-=shrink;
  366.           /*}}}  */
  367.           /*}}}  */
  368.           /*{{{  all jmp's to M_END_MACRO to opt_end!, get jmp-on information*/
  369.           for (current=start;current!=end;)
  370.              switch (*current)
  371.               { CASES_M_CALL
  372.                 CASES_M_JMP
  373.                 CASES_M_JMP_FALSE
  374.                 CASES_M_JMP_TRUE
  375.                    next=jmp_dest(current);
  376.                    buff[next-start]=1;
  377.                    current++;
  378.                    continue;
  379.                 case M_CALL:
  380.                 case M_JMP:
  381.                 case M_JMP_FALSE:
  382.                 case M_JMP_TRUE:
  383.                    next=jmp_dest(current);
  384.                    buff[next-start]=1;
  385.                    current+=2;
  386.                    continue;
  387.                 default:
  388.                    current=next_command(current);
  389.                    continue;
  390.               }
  391.           /*}}}  */
  392.           /*{{{  modify some OCL-assembler patterns*/
  393.           for (current=start;current!=end;)
  394.            { TOKEN cur_token;
  395.  
  396.              cur_token = *current;
  397.              next=next_command(current);
  398.              switch (opt_type)
  399.               {
  400.                 case set_no_test:
  401.                  /*{{{  no explicit test after some commands*/
  402.                    switch (cur_token)
  403.                     { default:
  404.                          goto skip_code;
  405.                       case M_ADD_COUNTER:
  406.                       case M_SUM_COUNTER:
  407.                       case M_INV_COUNTER:
  408.                          if
  409.                           (    next!=end
  410.                             && next[0]==M_NULL_COUNTER
  411.                             && current[1]==next[1]
  412.                             && !jumped_on(next,next+2)
  413.                           )
  414.                           { current=next;
  415.                             *current++=O_NOP;
  416.                             *current++=O_NOP;
  417.                             goto modif_code;
  418.                           }
  419.                          goto skip_code;
  420.                     }
  421.                  /*}}}  */
  422.                 case set_fixed_cmd:
  423.                  /*{{{  gen fixed argument commands*/
  424.                    switch(cur_token)
  425.                     { case M_ADD_COUNTER:
  426.                       case M_SET_COUNTER:
  427.                          if
  428.                           /*{{{  adding argument in fixed range*/
  429.                           (    current[2]<=FIXED_COMMAND_RANGE
  430.                             && current[2]>=-FIXED_COMMAND_RANGE
  431.                           )
  432.                           /*}}}  */
  433.                           /*{{{  fixed argument version*/
  434.                           { current[0]+=RANGE_ADD+current[2];
  435.                             current[2]=O_NOP;
  436.                             current+=3;
  437.                             goto modif_code;
  438.                           }
  439.                           /*}}}  */
  440.                          break;
  441.                       case M_CALL:
  442.                       case M_JMP:
  443.                       case M_JMP_TRUE:
  444.                       case M_JMP_FALSE:
  445.                          if
  446.                           /*{{{  jmp arg in fixed range*/
  447.                           (    current[1]<FIXED_COMMAND_RANGE
  448.                             && current[1]>=-FIXED_COMMAND_RANGE-1
  449.                           )
  450.                           /*}}}  */
  451.                           /*{{{  fixed argument version*/
  452.                           { current[0] = cur_token+RANGE_ADD+current[1]+1;
  453.                             current[1] = O_NOP;
  454.                             current+=2;
  455.                             goto modif_code;
  456.                           }
  457.                           /*}}}  */
  458.                          break;
  459.                       default:
  460.                          break;
  461.                     }
  462.                    goto skip_code;
  463.                  /*}}}  */
  464.                 case cut_strings:
  465.                  /*{{{  maybe shrink string*/
  466.                  { if (cur_token>O_NOP && cur_token<O_EXE_MACRO)
  467.                     /*{{{  handle prompt-strings*/
  468.                     { TOKEN *p_start;
  469.  
  470.                       p_start=current+1;
  471.                       switch(cmd_type[*current-O_NOP])
  472.                        { case COM_IIP:
  473.                           /*{{{  skip arg*/
  474.                             p_start++;
  475.                           /*}}}  */
  476.                          case COM_IP:
  477.                           /*{{{  skip arg*/
  478.                             p_start++;
  479.                           /*}}}  */
  480.                          case COM_P:
  481.                           /*{{{  maybe define message*/
  482.                           { int lg;
  483.                             int x;
  484.  
  485.                             /*{{{  get length of string*/
  486.                             for (lg=0;;p_start++)
  487.                              { if (*p_start<=0 || *p_start>=O_NOP)
  488.                                 { if (lg>=STR_CUT_LG)
  489.                                      break;
  490.                                   lg=0;
  491.                                   if
  492.                                    (    *p_start==M_INT_STRING
  493.                                      || *p_start==M_GET_HISTORY
  494.                                    )
  495.                                      p_start++;
  496.                                   else if (*p_start==M_END_MACRO)
  497.                                      break;
  498.                                 }
  499.                                else
  500.                                   lg++;
  501.                              }
  502.                             /*}}}  */
  503.                             for (x=0;lg-x>=STR_CUT_LG;x++)
  504.                              { TOKEN new;
  505.  
  506.                                if ((new=write_string(p_start-lg,lg-x,rc_string_gen)))
  507.                                 { TOKEN *source;
  508.                                   TOKEN *dest;
  509.  
  510.                                   *(p_start-1-x)= -new;
  511.                                   /*{{{  shift*/
  512.                                   for
  513.                                    ( source=p_start-1-lg,dest=p_start-2-x
  514.                                    ; source>=current
  515.                                    ; source-=1,dest-=1
  516.                                    )
  517.                                      *dest= *source;
  518.                                   /*}}}  */
  519.                                   /*{{{  fill with O_NOP*/
  520.                                   for (lg-=x;--lg;)
  521.                                      *current++=O_NOP;
  522.                                   /*}}}  */
  523.                                   goto modif_code;
  524.                                 }
  525.                              }
  526.                           }
  527.                           /*}}}  */
  528.                          default:
  529.                             break;
  530.                        }
  531.                     }
  532.                     /*}}}  */
  533.                    else if (cur_token<O_NOP && cur_token>0)
  534.                     /*{{{  handle text_string*/
  535.                     { TOKEN *str;
  536.                       int lg;
  537.  
  538.                       for
  539.                        ( str=current+1,lg=1
  540.                        ;    str!=end
  541.                          && *str>0
  542.                          && *str<O_NOP
  543.                          && !jumped_on(str,str+1)
  544.                          && lg<128
  545.                        ; str++,lg++
  546.                        );
  547.                       if (lg>=STR_CUT_LG+1)
  548.                        { TOKEN new;
  549.  
  550.                          if ((new=write_string(current,lg,rc_string_gen)))
  551.                           { *current++=M_ASCII;
  552.                             *current++= -new;
  553.                             while (current!=str)
  554.                                *current++=O_NOP;
  555.                             goto modif_code;
  556.                           }
  557.                        }
  558.                     }
  559.                     /*}}}  */
  560.                    goto default_opti;
  561.                  }
  562.                  /*}}}  */
  563.                 default:
  564.                 default_opti:
  565.                  /*{{{  normal command optimization*/
  566.                    switch (cur_token)
  567.                     {
  568.                       /*{{{  M_CALL        ...*/
  569.                       case M_CALL:
  570.                          dest=jmp_dest(current);
  571.                          if
  572.                           /*{{{  M_CALL x;M_END_MACRO -> M_JMP x; M_END_MACRO*/
  573.                           (next!=end && *next==M_END_MACRO)
  574.                           { *current=M_JMP;
  575.                             current=next;
  576.                             goto modif_code;
  577.                           }
  578.                           /*}}}  */
  579.                          else if
  580.                           /*{{{  M_CALL x; .. x:M_END_MACRO -> O_NOP; O_NOP; ..*/
  581.                           ( dest!=end && *dest==M_END_MACRO )
  582.                           { *current++=O_NOP;
  583.                             *current++=O_NOP;
  584.                             goto modif_code;
  585.                           }
  586.                           /*}}}  */
  587.                          goto skip_code;
  588.                       /*}}}  */
  589.                       /*{{{  M_JMP         ...*/
  590.                       case M_JMP:
  591.                          dest=jmp_dest(current);
  592.                          if
  593.                           /*{{{  M_JMP x; .. x:M_END_MACRO -> M_END_MACRO; O_NOP; ..*/
  594.                           ( dest!=end && *dest==M_END_MACRO)
  595.                           { *current++=M_END_MACRO;
  596.                             *current++=O_NOP;
  597.                             goto modif_code;
  598.                           }
  599.                           /*}}}  */
  600.                          else if
  601.                           /*{{{  M_JMP x;x: -> O_NOP; O_NOP;*/
  602.                           (dest==next)
  603.                           { *current++=O_NOP;
  604.                             *current++=O_NOP;
  605.                             goto modif_code;
  606.                           }
  607.                           /*}}}  */
  608.                          goto skip_code;
  609.                       /*}}}  */
  610.                       /*{{{  M_JMP_?       ...*/
  611.                       case M_JMP_FALSE:
  612.                       case M_JMP_TRUE:
  613.                          dest=jmp_dest(current);
  614.                          if
  615.                           /*{{{  M_JMP_COND x;x: -> O_NOP;O_NOP;*/
  616.                           (dest==next)
  617.                           { *current++=O_NOP;
  618.                             *current++=O_NOP;
  619.                             goto modif_code;
  620.                           }
  621.                           /*}}}  */
  622.                          else if
  623.                           /*{{{  M_JMP_COND x;M_JMP_COND y; -> M_JMP_COND x;[O_NOP;O_NOP]|[M_JMP y]*/
  624.                           (    next!=end
  625.                             && (*next==M_JMP_FALSE || *next==M_JMP_TRUE)
  626.                             && !jumped_on(next,next+2)
  627.                           )
  628.                           { if (*next==cur_token)
  629.                              { current+=2;
  630.                                *current++=O_NOP;
  631.                                *current++=O_NOP;
  632.                              }
  633.                             else
  634.                              { current+=2;
  635.                                *current++=M_JMP;
  636.                                current++;
  637.                              }
  638.                             goto modif_code;
  639.                           }
  640.                           /*}}}  */
  641.                          goto skip_code;
  642.                       /*}}}  */
  643.                       /*{{{  M_END_MACRO   ...*/
  644.                       case M_END_MACRO:
  645.                          if
  646.                           /*{{{  M_END M_END -> O_NOP M_END*/
  647.                           (next!=end && *next==M_END_MACRO)
  648.                           { *current++=O_NOP;
  649.                             goto modif_code;
  650.                           }
  651.                           /*}}}  */
  652.                          goto skip_code;
  653.                       /*}}}  */
  654.                       /*{{{  M_ADD_COUNTER ...*/
  655.                       case M_ADD_COUNTER:
  656.                          if
  657.                           /*{{{  ADD x 0 -> NOP NOP NOP*/
  658.                           ( *(current+2)==0 )
  659.                           { *current++=O_NOP;
  660.                             *current++=O_NOP;
  661.                             *current++=O_NOP;
  662.                             goto modif_code;
  663.                           }
  664.                           /*}}}  */
  665.                          else if (next!=end && !jumped_on(next,next_command(next)))
  666.                           { if
  667.                              /*{{{  ADD x n ADD x m -> NOP NOP NOP ADD X n+m*/
  668.                              (*next==M_ADD_COUNTER && *(next+1)==*(current+1))
  669.                              { *(next+2)+=*(current+2);
  670.                                *current++=O_NOP;
  671.                                *current++=O_NOP;
  672.                                *current++=O_NOP;
  673.                                goto modif_code;
  674.                              }
  675.                              /*}}}  */
  676.                           }
  677.                          goto skip_code;
  678.                       /*}}}  */
  679.                       /*{{{  some complex statements sequences*/
  680.                       default:
  681.                          if (next!=end)
  682.                           { TOKEN *n_next;
  683.  
  684.                             n_next=next_command(next);
  685.                             if (!jumped_on(next,n_next))
  686.                                switch (cur_token)
  687.                                 {
  688.                                   /*{{{  M_PUSH_INT    ...*/
  689.                                   case M_PUSH_INT:
  690.                                      if (*next==M_POP_INT)
  691.                                         if
  692.                                          /*{{{  PUSH x POP x -> NOP*/
  693.                                          (*(next+1)==*(current+1))
  694.                                          { *current++=O_NOP;
  695.                                            *current++=O_NOP;
  696.                                            *current++=O_NOP;
  697.                                            *current++=O_NOP;
  698.                                            goto modif_code;
  699.                                          }
  700.                                          /*}}}  */
  701.                                         else if
  702.                                          /*{{{  PUSH y POP x ADD x n -> SET x n SUM x y*/
  703.                                          (   next+2!=end
  704.                                           && *(next+2)==M_ADD_COUNTER
  705.                                           && *(next+3)==*(next+1)
  706.                                           && !(jumped_on(next+2,next+4))
  707.                                          )
  708.                                          { int n= *(next+4);
  709.                                            int x= *(next+1);
  710.                                            int y= *(current+1);
  711.  
  712.                                            *current++=O_NOP;
  713.                                            *current++=M_SET_COUNTER;
  714.                                            *current++=(TOKEN)x;
  715.                                            *current++=(TOKEN)n;
  716.                                            *current++=M_SUM_COUNTER;
  717.                                            *current++=(TOKEN)x;
  718.                                            *current++=(TOKEN)y;
  719.                                            goto modif_code;
  720.                                          }
  721.                                          /*}}}  */
  722.                                         else if
  723.                                          /*{{{  PUSH x POP y INV y SUM y z INV y -> PUSH z POP y INV y SUM y x NOP NOP*/
  724.                                          (   (current+11)<end
  725.                                           && !jumped_on(current,current+11)
  726.                                           && *(next+2)==M_INV_COUNTER
  727.                                           && *(next+4)==M_SUM_COUNTER
  728.                                           && *(next+7)==M_INV_COUNTER
  729.                                           && *(next+1)==*(next+3)
  730.                                           && *(next+1)==*(next+5)
  731.                                           && *(next+1)==*(next+8)
  732.                                          )
  733.                                          { int x=*(current+1);
  734.                                            int y=*(next+1);
  735.                                            int z=*(next+6);
  736.  
  737.                                            *current++=M_PUSH_INT;
  738.                                            *current++=(TOKEN)z;
  739.                                            *current++=M_POP_INT;
  740.                                            *current++=(TOKEN)y;
  741.                                            *current++=M_INV_COUNTER;
  742.                                            *current++=(TOKEN)y;
  743.                                            *current++=M_SUM_COUNTER;
  744.                                            *current++=(TOKEN)y;
  745.                                            *current++=(TOKEN)x;
  746.                                            *current++=O_NOP;
  747.                                            *current++=O_NOP;
  748.                                            goto modif_code;
  749.                                          }
  750.                                          /*}}}  */
  751.                                         else if
  752.                                          /*{{{  PUSH x POP dummy TEST dummy -> NOP NOP NOP NOP TEST x*/
  753.                                          (    isdummy(*(next+1))
  754.                                            && next+2!=end
  755.                                            && (*(next+2)==M_NULL_COUNTER || *(next+2)==M_POSITIV_COUNTER)
  756.                                            && !jumped_on(next+2,next+4)
  757.                                            && *(next+3)==*(next+1)
  758.                                          )
  759.                                          { *(next+3)=*(current+1);
  760.                                            *current++=O_NOP;
  761.                                            *current++=O_NOP;
  762.                                            *current++=O_NOP;
  763.                                            *current++=O_NOP;
  764.                                            goto modif_code;
  765.                                          }
  766.                                          /*}}}  */
  767.                                         else if
  768.                                          /*{{{  PUSH x POP dummy SUM y dummy -> NOP NOP NOP NOP SUM y x*/
  769.                                          (    isdummy(*(next+1))
  770.                                            && next+2!=end
  771.                                            && *(next+2)==M_SUM_COUNTER
  772.                                            && !jumped_on(next+2,next+5)
  773.                                            && *(next+4)==*(next+1)
  774.                                          )
  775.                                          { *(next+4)=*(current+1);
  776.                                            *current++=O_NOP;
  777.                                            *current++=O_NOP;
  778.                                            *current++=O_NOP;
  779.                                            *current++=O_NOP;
  780.                                            goto modif_code;
  781.                                          }
  782.                                          /*}}}  */
  783.                                      goto skip_code;
  784.                                   /*}}}  */
  785.                                   /*{{{  M_INV         ...*/
  786.                                   case M_INV_COUNTER:
  787.                                      if
  788.                                       /*{{{  INV x INV x -> NOP NOP NOP NOP*/
  789.                                       (*next==M_INV_COUNTER && *(current+1)==*(next+1))
  790.                                       { *current++=O_NOP;
  791.                                         *current++=O_NOP;
  792.                                         *current++=O_NOP;
  793.                                         *current++=O_NOP;
  794.                                         goto modif_code;
  795.                                       }
  796.                                       /*}}}  */
  797.                                      else if
  798.                                       /*{{{  INV x ADD x n -> ADD x -n INV x*/
  799.                                       ( *next==M_ADD_COUNTER && *(current+1)==*(next+1))
  800.                                       { int x= *(current+1);
  801.                                         int n= -*(next+2);
  802.  
  803.                                         *current++=M_ADD_COUNTER;
  804.                                         *current++=x;
  805.                                         *current++=n;
  806.                                         *current=M_INV_COUNTER;
  807.                                         *(current+1)=x;
  808.                                         goto modif_code;
  809.                                       }
  810.                                       /*}}}  */
  811.                                      else if
  812.                                       /*{{{  INV dummy NULL_COUNTER dummy -> NOP NOP NULL_COUNTER dummy*/
  813.                                       (    next[0]==M_NULL_COUNTER
  814.                                         && next[1]==current[1]
  815.                                         && isdummy(current[1])
  816.                                       )
  817.                                       { *current++=O_NOP;
  818.                                         *current=O_NOP;
  819.                                         current=n_next;
  820.                                         goto modif_code;
  821.                                       }
  822.                                       /*}}}  */
  823.                                      goto skip_code;
  824.                                   /*}}}  */
  825.                                   /*{{{  M_SUM_COUNTER ...*/
  826.                                   case M_SUM_COUNTER:
  827.                                      if
  828.                                       /*{{{  SUM x y ADD x n -> ADD x n SUM x y*/
  829.                                       (   *next==M_ADD_COUNTER
  830.                                        && *(current+1)==*(next+1)
  831.                                        && *(current+1)!=*(current+2)
  832.                                       )
  833.                                       { int n= *(next+2);
  834.                                         int y= *(current+2);
  835.  
  836.                                         *current++=M_ADD_COUNTER;
  837.                                         current++;
  838.                                         *current++=n;
  839.                                         *current++=M_SUM_COUNTER;
  840.                                         current++;
  841.                                         *current++=y;
  842.                                         goto modif_code;
  843.                                       }
  844.                                       /*}}}  */
  845.                                      goto skip_code;
  846.                                   /*}}}  */
  847.                                   /*{{{  M_ECHO_P      ...*/
  848.                                   case M_ECHO_P:
  849.                                      if (*next==M_ECHO_P && (n_next-current)<32)
  850.                                       { TOKEN *s,*d;
  851.  
  852.                                         for (s=next-2,d=next;s>=current;*d--= *s--);
  853.                                         *current++=O_NOP;
  854.                                         *current++=O_NOP;
  855.                                         goto modif_code;
  856.                                       }
  857.                                      goto skip_code;
  858.                                   /*}}}  */
  859.                                   /*{{{  M_SET_COUNTER ...*/
  860.                                   case M_SET_COUNTER:
  861.                                    { TOKEN *dest1=current+1;
  862.                                      TOKEN *dest2=next+1;
  863.                                      TOKEN *arg1=current+2;
  864.                                      TOKEN *arg2=next+2;
  865.  
  866.                                      if
  867.                                       /*{{{  SET x n;INV x -> SET x -n; NOP NOP*/
  868.                                       (*next==M_INV_COUNTER && *dest2==*dest1)
  869.                                       { *arg1= -*arg1;
  870.                                         *next++=O_NOP;
  871.                                         *next++=O_NOP;
  872.                                         current=next;
  873.                                         goto modif_code;
  874.                                       }
  875.                                       /*}}}  */
  876.                                      else if
  877.                                       /*{{{  SET x n; SET x m; -> NOP NOP NOP SET x m*/
  878.                                       (*next==M_SET_COUNTER && *dest2==*dest1)
  879.                                       { *current++=O_NOP;
  880.                                         *current++=O_NOP;
  881.                                         *current++=O_NOP;
  882.                                         goto modif_code;
  883.                                       }
  884.                                       /*}}}  */
  885.                                      else if
  886.                                       /*{{{  SET x n; SUM y x; -> SET x n; ADD y n | NOP NOP NOP ADD y n*/
  887.                                       (*next==M_SUM_COUNTER && *arg2==*dest1)
  888.                                       {  *next=M_ADD_COUNTER;
  889.                                          *arg2= *arg1;
  890.                                          if (isdummy(*dest1))
  891.                                           { *current++=O_NOP;
  892.                                             *current++=O_NOP;
  893.                                             *current++=O_NOP;
  894.                                           }
  895.                                          else
  896.                                           { current+=3;
  897.                                           }
  898.                                          goto modif_code;
  899.                                       }
  900.                                       /*}}}  */
  901.                                      else if
  902.                                       /*{{{  SET x 0; SUM x y; -> PUSH y POP x NOP NOP*/
  903.                                       ( *next==M_SUM_COUNTER && *dest2==*dest1 && *arg1==0)
  904.                                       { int s=*arg2;
  905.                                         int d=*dest1;
  906.  
  907.                                         *current++=M_PUSH_INT;
  908.                                         *current++=(TOKEN)s;
  909.                                         *current++=M_POP_INT;
  910.                                         *current++=(TOKEN)d;
  911.                                         *current++=O_NOP;
  912.                                         *current++=O_NOP;
  913.                                         goto modif_code;
  914.                                       }
  915.                                       /*}}}  */
  916.                                      else if
  917.                                       /*{{{  SET x n; ADD x m; -> NOP NOP NOP SET x n+m*/
  918.                                       (*next==M_ADD_COUNTER && *dest2==*dest1)
  919.                                       { *arg2+=*arg1;
  920.                                         *current++=O_NOP;
  921.                                         *current++=O_NOP;
  922.                                         *current++=O_NOP;
  923.                                         *current=M_SET_COUNTER;
  924.                                         goto modif_code;
  925.                                       }
  926.                                       /*}}}  */
  927.                                      else if
  928.                                       /*{{{  SET x n ASCII x -> SET X n ; n; | NOP NOP NOP n*/
  929.                                       (*next==M_ASCII && *dest2==*dest1 && next_command(dest1)==next)
  930.                                       { *next++ = *arg1;
  931.                                         *next++ = O_NOP;
  932.                                         if (isdummy(*dest1))
  933.                                          { *current++=O_NOP;
  934.                                            *current++=O_NOP;
  935.                                            *current=O_NOP;
  936.                                          }
  937.                                         current=next;
  938.                                         goto modif_code;
  939.                                       }
  940.                                       /*}}}  */
  941.                                      else if
  942.                                       /*{{{  SET x n TEST x JMP_cond d -> SET x n NOP NOP JMP d*/
  943.                                       (    (    *next==M_NULL_COUNTER
  944.                                              || *next==M_POSITIV_COUNTER
  945.                                            )
  946.                                         && *(next+1)==*(current+1)
  947.                                         && (next+2)!=end
  948.                                         && (    *(next+2)==M_JMP_TRUE
  949.                                              || *(next+2)==M_JMP_FALSE
  950.                                            )
  951.                                         && !jumped_on(next+2,next+4)
  952.                                       )
  953.                                       { boolean jmp;
  954.  
  955.                                         jmp=(*next==M_POSITIV_COUNTER)?(*(current+2)>0):(*(current+2)==0);
  956.                                         if (isdummy(*(current+1)))
  957.                                          /*{{{  set dummy not needed*/
  958.                                          { *current++=O_NOP;*current++=O_NOP;*current++=O_NOP; }
  959.                                          /*}}}  */
  960.                                         /*{{{  test not needed*/
  961.                                         *next++=O_NOP;*next++=O_NOP;
  962.                                         /*}}}  */
  963.                                         if (*next!=M_JMP_TRUE) jmp = !jmp;
  964.                                         if (jmp)
  965.                                          /*{{{  jmp_cond -> jmp*/
  966.                                          { *next=M_JMP;
  967.                                            next+=2;
  968.                                          }
  969.                                          /*}}}  */
  970.                                         else
  971.                                          /*{{{  jmp not needed*/
  972.                                          { *next++=O_NOP;
  973.                                            *next++=O_NOP;
  974.                                          }
  975.                                          /*}}}  */
  976.                                         current=next;
  977.                                         goto modif_code;
  978.                                       }
  979.                                       /*}}}  */
  980.                                      else if
  981.                                       /*{{{  SET x n TEST_CHARxxx dummy -> [SET x n;] TEST_CHARxxx n*/
  982.                                       (   *(next+1)==*(current+1)
  983.                                        && (*next==M_TEST_CC || *next==M_TEST_H_CC || *next==M_TEST_L_CC)
  984.                                       )
  985.                                       { switch (*next)
  986.                                          { case M_TEST_H_CC: *next=M_TEST_CHAR_HIGH;break;
  987.                                            case M_TEST_L_CC: *next=M_TEST_CHAR_LOW; break;
  988.                                            default:          *next=M_TEST_CHAR;     break;
  989.                                          }
  990.                                         *(next+1)=*(current+2);
  991.                                         if (isdummy(*(current+1)))
  992.                                          { *current++=O_NOP;*current++=O_NOP;*current++=O_NOP; }
  993.                                         else
  994.                                            current=next;
  995.                                         goto modif_code;
  996.                                       }
  997.                                       /*}}}  */
  998.                                      else if
  999.                                       /*{{{  SET dummy n PUSH dummy POP x -> SET x n NOP NOP NOP NOP*/
  1000.                                       (    isdummy(*dest1)
  1001.                                         && *next==M_PUSH_INT
  1002.                                         && *dest1==*dest2
  1003.                                         && (next+2)!=end
  1004.                                         && *(next+2)==M_POP_INT
  1005.                                         && !jumped_on(next+2,next+4)
  1006.                                       )
  1007.                                       { *dest1= *(next+3);
  1008.                                         *next++=O_NOP;
  1009.                                         *next++=O_NOP;
  1010.                                         *next++=O_NOP;
  1011.                                         *next++=O_NOP;
  1012.                                         current=next;
  1013.                                         goto modif_code;
  1014.                                       }
  1015.                                       /*}}}  */
  1016.                                      else if
  1017.                                       /*{{{  SET dummy n M_ECHO_I dummy -> M_ECHO_P n&255 M_END_MACRO O_NOP*/
  1018.                                       (    isdummy(*dest1)
  1019.                                         && *next==M_ECHO_I
  1020.                                         && *dest1==*dest2
  1021.                                       )
  1022.                                       { *current++=M_ECHO_P;
  1023.                                         *current++=(*arg1)&(O_NOP-1);
  1024.                                         *current++=M_END_MACRO;
  1025.                                         *current++=O_NOP;
  1026.                                         *current++=O_NOP;
  1027.                                         goto modif_code;
  1028.                                       }
  1029.                                       /*}}}  */
  1030.                                      else if
  1031.                                       /*{{{  SET dummy n M_LOAD_MAC x  dummy -> M_LOAD_MAC x -n*/
  1032.                                       (    isdummy(*dest1)
  1033.                                         && *next==M_LOAD_MAC
  1034.                                         && *arg2==*dest1
  1035.                                       )
  1036.                                       { int n;
  1037.  
  1038.                                         n= *arg1;
  1039.                                         *current++=M_LOAD_MAC;
  1040.                                         *current++= *dest2;
  1041.                                         *current++= -n;
  1042.                                         *current++=O_NOP;
  1043.                                         *current++=O_NOP;
  1044.                                         *current++=O_NOP;
  1045.                                         goto modif_code;
  1046.                                       }
  1047.                                       /*}}}  */
  1048.                                      goto skip_code;
  1049.                                    }
  1050.                                   /*}}}  */
  1051.                                   default:
  1052.                                      goto skip_code;
  1053.                                 }
  1054.                           }
  1055.                       /*}}}  */
  1056.                       skip_code:
  1057.                        /*{{{  set current to next and loop*/
  1058.                          current=next;
  1059.                          continue;
  1060.                        /*}}}  */
  1061.                       modif_code:
  1062.                        /*{{{  count modifications and loop*/
  1063.                          changed=True;
  1064.                          modified++;
  1065.                          continue;
  1066.                        /*}}}  */
  1067.                     }
  1068.                  /*}}}  */
  1069.               }
  1070.            }
  1071.           /*}}}  */
  1072.         }
  1073.         /*}}}  */
  1074.         if (verbose_level>1)
  1075.          /*{{{  maybe print current optimization strip*/
  1076.          { s_jmp_cut+=jmp_cut;
  1077.            s_modified+=modified;
  1078.            s_shrink+=shrink;
  1079.            loop++;
  1080.            if (jmp_cut+modified+shrink && verbose_level>2)
  1081.               fprintf(stderr,F_OPT_FORMAT,loop,jmp_cut,modified,shrink);
  1082.          }
  1083.          /*}}}  */
  1084.         if (!changed)
  1085.          { opt_type++;
  1086.            if (opt_type==set_fixed_cmd && !fix_args)
  1087.               opt_type++;
  1088.            if (opt_type!=opt_ready)
  1089.               changed=True;
  1090.          }
  1091.       }
  1092.       /*}}}  */
  1093.      while (changed && loop_max-->0);
  1094.      /*{{{  check correct usage of arguments*/
  1095.      { TOKEN *current;
  1096.  
  1097.        for (current=start;current!=end;)
  1098.         { switch (*current)
  1099.            { TOKEN x;
  1100.  
  1101.              /*{{{  M_TEST_CHARxxx check char!*/
  1102.              case M_TEST_CHAR:
  1103.              case M_TEST_CHAR_LOW:
  1104.              case M_TEST_CHAR_HIGH:
  1105.                 x= *(current+1);
  1106.                 current+=2;
  1107.                 if (x<0 || x>=O_NOP)
  1108.                    goto warn_char;
  1109.                 break;
  1110.              /*}}}  */
  1111.              /*{{{  O_LANGUAGE     check char!*/
  1112.              case O_LANGUAGE:
  1113.                 current+=1;
  1114.                 if (current!=end)
  1115.                  { x= *current;
  1116.                    if (x>=0 && x<O_NOP)
  1117.                     { char **s;
  1118.                 
  1119.                       for (s=f_c_name,x=toupper(x);;s++)
  1120.                          if (**s==x)
  1121.                             break;
  1122.                          else if (!**s)
  1123.              warn_char:{ error_po();
  1124.                             fprintf
  1125.                              ( stderr,
  1126.                                F_WARN_CHAR,
  1127.                                x,
  1128.                                (100*(current-start))/(end-start)
  1129.                              );
  1130.                             break;
  1131.                           }
  1132.                     }
  1133.                  }
  1134.                 break;
  1135.              /*}}}  */
  1136.              default:
  1137.                 current=next_command(current);
  1138.                 break;
  1139.            }
  1140.         }
  1141.  
  1142.      }
  1143.      /*}}}  */
  1144.      if (verbose_level>1)
  1145.       /*{{{  maybe print current optimization strip*/
  1146.       if ((verbose_level==2 || loop>1) && s_jmp_cut+s_modified+s_shrink)
  1147.         fprintf(stderr,F_OPT_S_FORMAT,loop-1,s_jmp_cut,s_modified,s_shrink);
  1148.       /*}}}  */
  1149.      return(end);
  1150.    }
  1151.    /*}}}  */
  1152. #endif
  1153.